from logging import getLogger
from urllib import quote

from zope import schema
from zope.component import getMultiAdapter
from zope.formlib import form
from zope.interface import implements

from plone.app.portlets.portlets import base
from plone.memoize import ram, instance
from plone.memoize.compress import xhtml_compress
from plone.portlets.interfaces import IPortletDataProvider
from plone.app.portlets.cache import render_cachekey

from Acquisition import aq_inner
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone import PloneMessageFactory as _

from meercat.ui.plone import labeledFilterQueryFieldExpression
from meercat.ui.plone.browser.portlets.facetBase import BaseFacetRenderer



log = getLogger('meercat.ui.plone.browser.portlets.facetField')

class IFacetFieldPortlet(IPortletDataProvider):
    
    label = schema.TextLine(title=_(u'Title'),
                            required=True)
    
    field = schema.TextLine(title=_(u'Field'),
                            description=_(u'The field to facet on.'),
                            required=True)
    
    prefix = schema.TextLine(title=_(u'Prefix'),
                             description=_('Limit facet terms to those with this prefix'),
                             required=False)
    
    limit = schema.Int(title=_(u'Limit'),
                       description=_(u'The default maximum number of facet '
                                     'values to return'),
                       required=False)
    
    mincount = schema.Int(title=_(u'Minimum'),
                          description=_(u'The minimum count for a facet value '
                                        'for it to be displayed.'),
                          required=False)
    
    missing = schema.Bool(title=_(u'Include Missing'),
                          description=_(u'If selected, counts for fields with '
                                        'no value are included. i.e. if there '
                                        'is a facet on subject, it will list '
                                        'off the number of documents matching '
                                        'the query that have no subject'),
                          required=False)
    
    sort = schema.Bool(title=_(u'Sort by value'),
                       description=_(u'If true, terms will be sorted by value '
                                     'instead of by count'),
                       default=False)
    
    always = schema.Bool(title=_(u'Always Available'),
                         description=_(u'If enabled, this portlet will still be '
                                       'available after one of the facets has '
                                       'been selected.'),
                         default=True)
    
class Assignment(base.Assignment):
    implements(IFacetFieldPortlet)
    
    def __init__(self, label, field, prefix=None, sort=True, limit=None,
                 mincount=None, missing=None, always=None):
        self.label = label
        self.field = field
        self.prefix = prefix
        self.sort = sort
        self.limit = limit
        self.mincount = mincount
        self.missing = missing
        self.always = always
    
    @property
    def title(self):
        return _(u"Facet Field: ") + self.label

class Renderer(BaseFacetRenderer):
    label = None
    field = None
    
    def getTitle(self):
        return self.label
    
    def __init__(self, *args, **kwargs):
        super(Renderer, self).__init__(*args, **kwargs)
        try:
            self.label = self.data.label
            self.field = self.data.field
        except:
            pass
    
    @property
    def available(self):
        if not super(Renderer, self).available:
            return False
        
        if self.data.always:
            return True
        
        return not self.field in self.getExistingFacetFilterFields()
    
    @instance.memoize
    def getExistingFacetFilterFields(self):
        fq = self.request.get('fq',[])
        
        if isinstance(fq, basestring):
            fq = [fq]
        
        return map(lambda f: f.groupdict()['field'],
                   filter(lambda f: f,
                          map(labeledFilterQueryFieldExpression.match, fq)))
    
    @instance.memoize
    def getQueryParameters(self):
        params = super(Renderer,self).getQueryParameters()
        
        if not params:
            log.debug('No parameters received from super call')
            return None
        
        params['facet.field'] = self.field
        
        if self.data.prefix:
            params['facet.prefix'] = self.data.prefix
        
        if self.data.limit:
            params['facet.limit'] = self.data.limit
        
        if self.data.mincount:
            params['facet.mincount'] = self.data.mincount
        
        if self.data.sort:
            if aq_inner(self.context).getMeercatManager().getSolrVersion() <= 1.3:
                params['facet.sort'] = 'false'
            else:
                params['facet.sort'] = 'index'
        
        if self.data.missing:
            params['facet.missing'] = 'true'
        
        return params
    
    def getFacets(self):
        facet_counts = self.getFacetCounts()
        
        if not facet_counts:
            log.debug('No facet counts')
            return None
                
        counts = facet_counts.get('facet_fields',{}).get(self.field,{})
        facets = []
        
        for value,count in counts.iteritems():
            facets.append({'value':value,
                           'count':count,
                           'url':self.view.getUrlWithParams(remove=['page'],
                                                            replace=False,
                                                            fq='%s(%s):"%s"' % (self.field,
                                                                                self.label,
                                                                                value,))})
        
        if self.data.sort:
            facets.sort(key=lambda f: f['value'].lower())
        else:
            facets.sort(key=lambda f: f['count'], reverse=True)
        
        return facets

class AddForm(base.AddForm):
    form_fields = form.Fields(IFacetFieldPortlet)
    label = _(u"Add Facet Field Portlet")
    description = _(u"This portlet lists facets for a field from a search.")
    
    def create(self, data):
        return Assignment(label=data.get('label'),
                          field=data.get('field'),
                          prefix=data.get('prefix',None),
                          sort=data.get('sort',None),
                          limit=data.get('limit',None),
                          mincount=data.get('mincount',None),
                          missing=data.get('missing',None),
                          always=data.get('always',None))

class EditForm(base.EditForm):
    form_fields = form.Fields(IFacetFieldPortlet)
    label = _(u"Edit Facet Field Portlet")
    description = AddForm.description
